﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;

namespace HypermarketSerialPort._2_Controller
{
    class CoordinatingController
    {
        //static private string STARTBYTE = "7E";  //7E
        static private string PROGRAM_ERROR = " There is an error, please try again!";
        static private string TYPE_ERROR = "Please type in a valid type!";
        //static private string STARTBYTEINFOR_ERROR = "The start byte of the information is not correct!";

        private static CoordinatingController mInstance;
        private _1_Model.LogInManager mLoginManager;
        private _1_Model.CheckInformationManager mCheckinfoManager;
        private _1_Model.CheckOutManager mCheckOutManager;
        private _1_Model.AddTransactionManager mAddTransactionManager;
        private _1_Model.CancelTransactionManager mCancelTransactionManager;

        private Dictionary<string, CashierRegister> mCashierRegisters;

        private ProtocolManager mPManager;

        private byte mLastState = 0x01;

        private CoordinatingController()
        {
            mCashierRegisters = new Dictionary<string, CashierRegister>();
            mPManager = ProtocolManager.getInstance();
            mLoginManager = _1_Model.LogInManager.getInstance();
            mCheckinfoManager = _1_Model.CheckInformationManager.getInstance();
            mCancelTransactionManager = _1_Model.CancelTransactionManager.getInstance();
            mAddTransactionManager = _1_Model.AddTransactionManager.getInstance();
            mCheckOutManager = _1_Model.CheckOutManager.getInstance(); 
        }

        public static CoordinatingController getInstance()
        {
            if (mInstance == null)
            {
                mInstance = new CoordinatingController();
            }
            return mInstance;
        }

        public byte[] StartOperation(byte[] input)
        {
            string outputStr = string.Empty;
            byte[] output;
            input = mPManager.ByteStuffingReceive(input.ToList());
//            List<string> commandList = mPManager.DemoProtocal(inputStr);
            byte state;
            if (input[2] == 0x04)
            {
                output = null;
                return output;
            }
            else
            {
                state = input[2];
            }

            switch (state)
            {
                case 0x01:
                    output = mPManager.GenerateBroadcast("01", MACHINE.CashierRegister);
                    break;

                case (byte)STATE.Authentication:
                    output = TestLogin(input);
                    break;

                case (byte)STATE.LogOut:
                    output = TestLogout(input);
                    break;

                case (byte)STATE.RequestPriceInfo:
                    output = TestRequestPriceInfo(input);
                    break;

                case (byte)STATE.TransactionVerify:
                    output = TestTransactionVerify(input);
                    break;

                case (byte)STATE.DeleteVerify:
                    output = TestDeleteVerify(input);
                    break;

                //case (byte)STATE.CancellationVerify:

                //    break;

                //case (byte)STATE.CheckOut:

                //    break;

                //case (byte)STATE.RequestLastItemInfo:

                //    break;

                //case (byte)STATE.DeleteLastItemVerifyState:

                //    break;


                default:
                    input = new byte[] {0x7E, 0x7D, 0x5e, 0x1F, 0x42, 0x56, 0x12, 0x7d, 0x5F, 0x7F};
                    output = TestLogin(input);
                //    outputStr = Operation(commandList);
                //    output = testUART(outputStr, commandList.First());
                    break;
            }
            mLastState = state;
            return output;
        }

        private byte[] testUART(string outputStr, string id)
        {
            string[] input = outputStr.Split(new char[] { '\r', '\n', ':' });
            List<string> data = new List<string> { id, "03", input[4], input[7] };
            byte[] output;
            output = mPManager.GeneratePriceTagReply(data).ToArray();
            return output;
        }

        public byte[] TestLogin(byte[] input)
        {
            if (mPManager.CheckStartAndEndByte(input))
            {
                if (mPManager.CheckEndOfCommunication(input))
                {
                    byte[] output = new byte[0];
                    return output;
                }
                List<string> loginInfo = mPManager.ConvertHexMessageToString(input);
                string o = Operation(loginInfo);
                int pos = o.IndexOf("Welcome ");
                if (o.IndexOf("Welcome ") != -1)
                {
                    List<string> outlist = new List<string> { input[1].ToString(), input[2].ToString(), "Y" };
                    byte[] output = mPManager.ConvertStringMessageToHex(outlist);
                    return output;
                }
                else
                {
                    List<string> outlist = new List<string> { input[1].ToString(), input[2].ToString(), "N" };
                    byte[] output = mPManager.ConvertStringMessageToHex(outlist);
                    return output;
                }
            }
            else
            {
                List<string> outlist = new List<string> { input[1].ToString(), input[2].ToString(), "N" };
                byte[] output = mPManager.ConvertStringMessageToHex(outlist);
                return output;
            }
        }

        public byte[] TestLogout(byte[] input)
        {
            if (mPManager.CheckStartAndEndByte(input))
            {
                if (mPManager.CheckEndOfCommunication(input))
                {
                    byte[] output = new byte[0];
                    return output;
                }
                else
                {
                    List<string> outlist = new List<string> { input[1].ToString(), input[2].ToString(), "Y" };
                    byte[] output = mPManager.ConvertStringMessageToHex(outlist);
                    return output;
                }
            }
            else
            {
                List<string> outlist = new List<string> { input[1].ToString(), input[2].ToString(), "N" };
                byte[] output = mPManager.ConvertStringMessageToHex(outlist);
                return output;
            }
        }

        public byte[] TestRequestPriceInfo(byte[] input)
        {
            if (mPManager.CheckStartAndEndByte(input))
            {
                if (mPManager.CheckEndOfCommunication(input))
                {
                    byte[] output = new byte[0];
                    return output;
                }
                else
                {
                    List<string> o = mPManager.ConvertHexMessageToString(input);
                    string outputStr = Operation(o);
                    string[] splitStr = outputStr.Split(new char[] { '\r', '\n', ':' });
                    List<string> outputList = new List<string> { input[1].ToString(), input[2].ToString(), "Y", splitStr[4].Trim(), splitStr[7].Trim() };
                    byte[] output = mPManager.ConvertStringMessageToHex(outputList);
                    return output;
                }
            }
            else
            {
                List<string> outlist = new List<string> { input[1].ToString(), input[2].ToString(), "N" };
                byte[] output = mPManager.ConvertStringMessageToHex(outlist);
                return output;
            }
        }

        public byte[] TestTransactionVerify(byte[] input)
        {
            if (mPManager.CheckStartAndEndByte(input))
            {
                if (mPManager.CheckEndOfCommunication(input))
                {
                    byte[] output = new byte[0];
                    return output;
                }
                else
                {
                    List<string> o = mPManager.ConvertHexMessageToString(input);
                    string outputStr = Operation(o);
                    string[] splitStr = outputStr.Split(new char[] { '\r', '\n', ':' });
                    List<string> outputList = new List<string> { input[1].ToString(), input[2].ToString(), "Y", splitStr[7].Trim(), splitStr[10].Trim() };
                    byte[] output = mPManager.ConvertStringMessageToHex(outputList);
                    return output;
                }
            }
            else
            {
                List<string> outlist = new List<string> { input[1].ToString(), input[2].ToString(), "N" };
                byte[] output = mPManager.ConvertStringMessageToHex(outlist);
                return output;
            }
        }

        public byte[] TestDeleteVerify(byte[] input)
        {
            if (mPManager.CheckStartAndEndByte(input))
            {
                if (mPManager.CheckEndOfCommunication(input))
                {
                    byte[] output = new byte[0];
                    return output;
                }
                else
                {
                    List<string> o = mPManager.ConvertHexMessageToString(input);
                    o.RemoveAt(o.Count - 1);
                    string outputStr = Operation(o);
                    List<string> outputList;
                    if (outputStr.IndexOf("Success") != -1)
                    {
                        outputList = new List<string> { input[1].ToString(), input[2].ToString(), "Y", "100.00" };
                    }
                    else
                    {
                        outputList = new List<string> { input[1].ToString(), input[2].ToString(), "N" };
                    }
                    byte[] output = mPManager.ConvertStringMessageToHex(outputList);
                    return output;
                }
            }
            else
            {
                List<string> outlist = new List<string> { input[1].ToString(), input[2].ToString(), "N" };
                byte[] output = mPManager.ConvertStringMessageToHex(outlist);
                return output;
            }
        }

        #region Operation
        public string Operation(List<string> serialPortInput)
        {
            try
            {
                int num_InfoType = int.Parse(serialPortInput[1]);
                serialPortInput.RemoveAt(1);
                switch (num_InfoType)
                {
                    #region CASE 01 Cashier Login
                    case 0x1F:
                        Console.WriteLine("Case Cashier LogIn");
                        return mLoginManager.OperationLogin(serialPortInput, mCashierRegisters);
                    #endregion


                    #region CASE 02 Check Product Information
                    case 02:
                    case 101:
                        Console.WriteLine("Case Check Product Information");
                        return mCheckinfoManager.OperationProducrtInfor(serialPortInput);
                    #endregion


                    #region CASE 03 Add Product Transaction
                    case 03:
                    case 37:
                        Console.WriteLine("Case Add Product Transaction");
                        return mAddTransactionManager.OperationAddTransaction(serialPortInput, mCashierRegisters);
                    #endregion


                    #region CASE 04 Cancel Transaction
                    case 04:
                    case 69:
                        Console.WriteLine("Case CancelLastTransaction");
                        //what's the format for cancel transaction
                        return mCancelTransactionManager.OperationCancelTransaction(serialPortInput, mCashierRegisters);
                    #endregion


                    #region CASE 05 Checkout iterms
                    case 05:
                        Console.WriteLine("Case CheckOut");
                        //check out, list of all the transactions
                        return mCheckOutManager.OperationCheckOut(serialPortInput, mCashierRegisters);
                    #endregion

                    default:
                        Console.WriteLine("not a valid case");
                        break;
                }
                return TYPE_ERROR;
            }
            catch
            {
                return PROGRAM_ERROR;
            }
        }
        #endregion

    }
}
